import json
import time
from django.utils.deprecation import MiddlewareMixin
from django.utils import timezone
from .models import SystemLog


class LoggingMiddleware(MiddlewareMixin):
    """系统日志记录中间件"""

    # 需要记录日志的路径前缀
    LOG_PATHS = [
        '/api/auth/',
        '/api/users/',
        '/api/courses/',
        '/api/enrollment/',
        '/api/my-enrollments/',
        '/api/statistics/'
    ]

    # 不记录日志的具体路径
    EXCLUDE_PATHS = [
        '/api/dashboard/stats/',
        '/api/student-course-status/',
    ]

    def process_request(self, request):
        """请求开始时记录开始时间"""
        request._start_time = time.time()
        return None

    def process_response(self, request, response):
        """请求结束时记录日志：生成和保存日志"""
        try:
            # 检查是否需要记录日志
            if not self._should_log(request):
                return response

            # 获取用户信息
            user_id = request.META.get('HTTP_USER_ID')
            user_role = request.META.get('HTTP_USER_ROLE')

            # 获取客户端信息
            client_ip = self._get_client_ip(request)
            user_agent = request.META.get('HTTP_USER_AGENT', '')

            # 确定操作类型和描述
            action, description, target_type, target_id = self._get_action_info(request, response)

            # 获取请求数据
            request_data = self._get_request_data(request)

            # 计算响应时间
            response_time = None
            if hasattr(request, '_start_time'):
                response_time = round((time.time() - request._start_time) * 1000, 2)

            # 创建日志记录
            log_data = {
                'action': action,
                'description': description,
                'target_type': target_type,
                'target_id': target_id,
                'ip_address': client_ip,
                'user_agent': user_agent,
                'request_data': request_data,
                'response_status': response.status_code,
            }

            # 如果有用户ID，关联用户
            if user_id:
                try:
                    from apps.users.models import User
                    user = User.objects.get(id=user_id)
                    log_data['user'] = user
                except User.DoesNotExist:
                    pass

            # 异步创建日志记录（避免影响主要业务）
            try:
                SystemLog.objects.create(**log_data)
            except Exception as e:
                # 日志记录失败不应该影响主要业务
                print(f"日志记录失败: {str(e)}")

        except Exception as e:
            # 中间件异常不应该影响主要业务
            print(f"日志中间件异常: {str(e)}")

        return response

    def _should_log(self, request):
        """判断是否需要记录日志"""
        path = request.path
        method = request.method

        # 只记录 API 请求
        if not path.startswith('/api/'):
            return False

        # 排除特定路径
        for exclude_path in self.EXCLUDE_PATHS:
            if path.startswith(exclude_path):
                return False

        # 检查是否在需要记录的路径中
        for log_path in self.LOG_PATHS:
            if path.startswith(log_path):
                return True

        return False

    def _get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    def _get_action_info(self, request, response):
        """根据请求路径和方法确定操作类型"""
        path = request.path
        method = request.method
        status_code = response.status_code

        action = f"{method}"
        description = ""
        target_type = None
        target_id = None

        # 解析路径获取资源类型和ID
        path_parts = [p for p in path.split('/') if p]

        try:
            if '/auth/login/' in path:
                action = "用户登录"
                description = f"用户尝试登录系统 - {self._get_status_desc(status_code)}"
                target_type = "auth"

            elif '/auth/logout/' in path:
                action = "用户登出"
                description = f"用户登出系统 - {self._get_status_desc(status_code)}"
                target_type = "auth"

            elif '/users/' in path:
                if method == 'GET' and path.endswith('/users/'):
                    action = "查看用户列表"
                    description = f"管理员查看用户列表 - {self._get_status_desc(status_code)}"
                    target_type = "user"
                elif method == 'POST' and ('create' in path or path.endswith('/users/')):
                    action = "创建用户"
                    description = f"管理员创建新用户 - {self._get_status_desc(status_code)}"
                    target_type = "user"
                elif method == 'GET' and any(p.isdigit() for p in path_parts):
                    user_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "查看用户详情"
                    description = f"查看用户详情 - {self._get_status_desc(status_code)}"
                    target_type = "user"
                    target_id = int(user_id) if user_id else None
                elif method == 'PUT':
                    user_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "更新用户"
                    description = f"管理员更新用户信息 - {self._get_status_desc(status_code)}"
                    target_type = "user"
                    target_id = int(user_id) if user_id else None
                elif method == 'DELETE':
                    user_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "删除用户"
                    description = f"管理员删除用户 - {self._get_status_desc(status_code)}"
                    target_type = "user"
                    target_id = int(user_id) if user_id else None
                elif method == 'PATCH' and 'status' in path:
                    user_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "更新用户状态"
                    description = f"管理员更新用户状态 - {self._get_status_desc(status_code)}"
                    target_type = "user"
                    target_id = int(user_id) if user_id else None

            elif '/courses/' in path:
                if method == 'GET' and path.endswith('/courses/'):
                    action = "查看课程列表"
                    description = f"查看课程列表 - {self._get_status_desc(status_code)}"
                    target_type = "course"
                elif method == 'POST' and path.endswith('/courses/'):
                    action = "创建课程"
                    description = f"创建新课程 - {self._get_status_desc(status_code)}"
                    target_type = "course"
                elif method == 'GET' and any(p.isdigit() for p in path_parts):
                    course_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "查看课程详情"
                    description = f"查看课程详情 - {self._get_status_desc(status_code)}"
                    target_type = "course"
                    target_id = int(course_id) if course_id else None
                elif method == 'PUT':
                    course_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "更新课程"
                    description = f"更新课程信息 - {self._get_status_desc(status_code)}"
                    target_type = "course"
                    target_id = int(course_id) if course_id else None
                elif method == 'DELETE':
                    course_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "删除课程"
                    description = f"删除课程 - {self._get_status_desc(status_code)}"
                    target_type = "course"
                    target_id = int(course_id) if course_id else None
                elif method == 'PATCH' and 'status' in path:
                    course_id = next((p for p in path_parts if p.isdigit()), None)
                    action = "更新课程状态"
                    description = f"更新课程状态 - {self._get_status_desc(status_code)}"
                    target_type = "course"
                    target_id = int(course_id) if course_id else None

            elif '/enrollment/' in path:
                if method == 'POST':
                    action = "学生选课"
                    description = f"学生选课操作 - {self._get_status_desc(status_code)}"
                    target_type = "enrollment"
                elif method == 'DELETE':
                    action = "学生退课"
                    description = f"学生退课操作 - {self._get_status_desc(status_code)}"
                    target_type = "enrollment"

            elif '/my-enrollments/' in path:
                action = "查看选课记录"
                description = f"学生查看选课记录 - {self._get_status_desc(status_code)}"
                target_type = "enrollment"

            elif '/statistics/' in path:
                action = "查看统计数据"
                description = f"查看系统统计数据 - {self._get_status_desc(status_code)}"
                target_type = "statistics"

            else:
                action = f"{method} {path}"
                description = f"API请求: {method} {path} - {self._get_status_desc(status_code)}"

        except Exception as e:
            action = f"{method} {path}"
            description = f"解析操作类型失败: {str(e)}"

        return action, description, target_type, target_id

    def _get_status_desc(self, status_code):
        """获取状态码描述"""
        if 200 <= status_code < 300:
            return "成功"
        elif 400 <= status_code < 500:
            return "客户端错误"
        elif 500 <= status_code < 600:
            return "服务器错误"
        else:
            return f"状态码{status_code}"

    def _get_request_data(self, request):
        """获取请求数据"""
        try:
            data = {}

            # 获取查询参数
            if request.GET:
                data['query_params'] = dict(request.GET)

            # 获取请求体数据
            if request.method in ['POST', 'PUT', 'PATCH']:
                content_type = request.content_type
                if 'application/json' in content_type:
                    try:
                        if hasattr(request, 'body') and request.body:
                            body_data = json.loads(request.body)
                            # 过滤敏感信息
                            if isinstance(body_data, dict):
                                filtered_data = {}
                                for key, value in body_data.items():
                                    if key.lower() in ['password', 'confirm_password', 'token']:
                                        filtered_data[key] = "***"
                                    else:
                                        filtered_data[key] = value
                                data['body'] = filtered_data
                    except (json.JSONDecodeError, UnicodeDecodeError):
                        data['body'] = "无法解析的请求体"

            # 限制数据大小
            data_str = json.dumps(data, ensure_ascii=False)
            if len(data_str) > 5000:
                data = {"message": "请求数据过大，已截断"}

            return data

        except Exception as e:
            return {"error": f"获取请求数据失败: {str(e)}"}